﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace MCWorldLibrary
{
    class Chunk
    {
        private NBT.Tag data;

        public int X { get; private set; }
        public int Z { get; private set; }

        public ChunkSection[] Sections { get; private set; }
        public Heightmap Heightmap { get; private set; }

        public Chunk(NBT.Tag data)
        {
            this.data = data;
            this.X = this.GetXPositionFromRootTag(data);
            this.Z = this.GetZPositionFromRootTag(data);
            this.Sections = new ChunkSection[16];

            NBT.Tag levelTag = (data.Payload as NBT.CompoundTagPayload).Value.First();

            this.Heightmap = new Heightmap((NBT.IntArrayPayload)(levelTag.Payload as NBT.CompoundTagPayload).Value.Single(x => x.Name == "HeightMap").Payload);

            NBT.Tag sectionsTag = (levelTag.Payload as NBT.CompoundTagPayload).Value.First(x => x.Name == "Sections");
            var sections = (sectionsTag.Payload as NBT.ListTagPayload).Value.Cast<NBT.CompoundTagPayload>();
            for (int i = 0; i < 16; ++i)
            {
                NBT.CompoundTagPayload sectionTag = sections.SingleOrDefault(x => (x.Value.Single(y => y.Name == "Y").Payload as NBT.BytePayload).Value == i);
                this.Sections[i] = new ChunkSection(this, sectionTag, i);

                if (sectionTag == null)
                {
                    (sectionsTag.Payload as NBT.ListTagPayload).Value.Add(this.Sections[i].SectionTag);
                }
            }
        }

        private int GetXPositionFromRootTag(NBT.Tag tag)
        {
            return (((tag.Payload as NBT.CompoundTagPayload).Value.Single().Payload as NBT.CompoundTagPayload).Value.First(o => o.Name == "xPos").Payload as NBT.IntPayload).Value;
        }

        private int GetZPositionFromRootTag(NBT.Tag tag)
        {
            return (((tag.Payload as NBT.CompoundTagPayload).Value.Single().Payload as NBT.CompoundTagPayload).Value.First(o => o.Name == "zPos").Payload as NBT.IntPayload).Value;
        }

        public void Serialize(MemoryStream stream)
        {
            this.data.Serialize(stream);
        }


        internal void RecalculateHeightMap()
        {
            for (int x = 0; x < 16; x++)
            {
                for (int z = 0; z < 16; z++)
                {
                    int max = GetHeightForColumn(x, z);
                    this.Heightmap.Set(x, max, z);
                }
            }
        }

        private int GetHeightForColumn(int x, int z)
        {
            for (int i = 15; i >= 0; i--)
            {
                for (int y = 15; y >= 0; y--)
                {
                    if (this.Sections[i].GetBlock(x, y, z) != 0)
                        return (i * 16) + y;
                }
            }

            return 0;
        }
    }
}
